package com.wyclabs.auth.common;

import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.wyclabs.cache.redis.RedisClient;
import com.wyclabs.commons.entity.JsonResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * 拦截 oauth/token 的返回值，对其进行封装
 * @author sr
 * @date 2019/10/28
 */
@Aspect
@Component
@Slf4j
public class TokenModifyAop {

    private static final String PRE_PROD_USER_PHONE = "pre-prod-user:phone";
    private static final String PRE_PROD_USER_MODNIM_NUM = "pre-prod-user:modnimnum";

    @Resource
    private RedisClient redisClient;

    @Pointcut("execution(* org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(..))")
    public void oauthTokenPointCut() {
    }

    /**
     * 对返回值进行拦截并修改
     */
    @Around(value = "oauthTokenPointCut()")
    private Object modifyTokenAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        Object responseObject = joinPoint.proceed();
        if (responseObject != null) {
            if (responseObject instanceof ResponseEntity) {
                ResponseEntity responseEntity = (ResponseEntity) responseObject;
                if (responseEntity.getBody() instanceof OAuth2AccessToken) {
                    OAuth2AccessToken oAuth2AccessToken = (OAuth2AccessToken) responseEntity
                            .getBody();
                    return getResponse(JsonResult.success(oAuth2AccessToken));
                }
            }
            return responseObject;
        }
        return null;
    }

    private ResponseEntity<JsonResult<OAuth2AccessToken>> getResponse(
            JsonResult<OAuth2AccessToken> accessToken) {
        OAuth2AccessToken o2at = accessToken.getData();

        HttpHeaders headers = new HttpHeaders();
        headers.set("Cache-Control", "no-store");
        headers.set("Pragma", "no-cache");
        headers.set("Content-Type", "application/json;charset=UTF-8");

        if (Objects.nonNull(o2at)) {
            String token = o2at.getValue();
            String phone = null;
            String modnimNum = null;

            try {
                DecodedJWT decode = JWT.decode(token);
                phone = decode.getClaim("phone").asString();
                modnimNum = decode.getClaim("modnimNum").asString();
            } catch (Exception e) {
                log.warn("JWT读取异常", e);
            }

            boolean isPreProd = (StringUtils.isNotEmpty(phone) && redisClient.sismember(PRE_PROD_USER_PHONE, phone)) || (StringUtils.isNotEmpty(modnimNum) && redisClient.sismember(PRE_PROD_USER_MODNIM_NUM, modnimNum));
            if (isPreProd) {
                headers.add("Access-Control-Expose-Headers", "Pre-Prod");
                headers.add("Access-Control-Expose-Headers", "pre-prod");
                headers.add("Pre-Prod", "1");
            }
        }

        return new ResponseEntity<>(accessToken, headers, HttpStatus.OK);
    }
}
